﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Data;
using System.Windows.Threading;

namespace ReportingManagement.Components.Validation
{
    public class ProxyElement : FrameworkElement
    {
        public static readonly DependencyProperty InProperty;
        public static readonly DependencyProperty OutProperty;

        static ProxyElement()
        {
            FrameworkPropertyMetadata inMetadata = new FrameworkPropertyMetadata();
            inMetadata.BindsTwoWayByDefault = false;
            inMetadata.DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            inMetadata.PropertyChangedCallback = new PropertyChangedCallback(OnInPropertyChanged);

            FrameworkPropertyMetadata outMetadata = new FrameworkPropertyMetadata();
            outMetadata.BindsTwoWayByDefault = true;
            outMetadata.DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            outMetadata.PropertyChangedCallback = new PropertyChangedCallback(OnOutPropertyChanged);

            OutProperty = DependencyProperty.Register("Out", typeof(object), typeof(ProxyElement), outMetadata);
            InProperty = DependencyProperty.Register("In", typeof(object), typeof(ProxyElement), inMetadata);
        }

        private static void OnInPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ProxyElement proxy = (ProxyElement)sender;
            proxy.Out = e.NewValue;
        }

        private static void OnOutPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ValueSource source = DependencyPropertyHelper.GetValueSource(sender, e.Property);
            if (source.BaseValueSource != BaseValueSource.Local)
            {
                ProxyElement proxy = (ProxyElement)sender;
                object expected = proxy.In;
                if (!object.ReferenceEquals(e.NewValue, expected))
                {
                    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.DataBind, (ThreadStart)(delegate
                        {
                            proxy.Out = proxy.In;
                        }));
                }
            }            
        }

        public ProxyElement()
        {
            this.Visibility = System.Windows.Visibility.Collapsed;
        }

        public object In
        {
            get { return this.GetValue(InProperty); }
            set { this.SetValue(InProperty, value); }
        }

        public object Out
        {
            get { return this.GetValue(OutProperty); }
            set { this.SetValue(OutProperty, value); }
        }
    }
}
